package com.cloud.async.business.context.data;

import com.cloud.async.flow.util.timer.SystemClock;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.ObjectUtils;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author chengr
 */
public class TimerDataSource<K, V> extends ConcurrentHashMap<K, V> {

    /**
     * logger
     */
    private final Log logger = LogFactory.getLog(getClass());

    /**
     * 定时器默认执行周期时间
     */
    private Integer executionCycleTimer = (30 * 1000);

    /**
     * 定时器
     */
    private final Timer timer = new Timer();

    /**
     * 同主Map共同步记录当前的数据（只存放时间）
     * LocalDataWrapper<V>
     */
    private ConcurrentHashMap<K, LocalDataWrapper<V>> timerRecord;

    /**
     * 定时器设置
     */
    private TimerTask timerTask = new TimerTask() {
        @Override
        public void run() {
            logger.info("TimerExpireDataSource timerTask start: " + SystemClock.now());
            //基于TimerRecord来看，该对象中timerRecord.keySet() >= super.keySet()
            KeySetView<K, LocalDataWrapper<V>> ks = timerRecord.keySet();
            timerRecord.keySet().removeIf(key -> {
                LocalDataWrapper<V> localDataWrapper = timerRecord.get(key);
                Integer time = localDataWrapper.getTime();
                if (time == 1) {
                    return true;
                } else {
                    //移除super中的数据并且添加到timerRecord
                    timerRecord.get(key).setFuture(TimerDataSource.super.remove(key));
                    timerRecord.get(key).setTime(1);
                    return false;
                }
            });
            logger.info("TimerExpireDataSource timerTask end: " + SystemClock.now());
        }
    };

    @Override
    public V put(K key, V value) {
        this.timerRecord.put(key, createNewLocalData());
        return super.put(key, value);
    }

    /**
     * 返回新的对象LocalDataWrapper
     * @return
     */
    private LocalDataWrapper<V> createNewLocalData() {
        LocalDataWrapper<V> dataWrapper = new LocalDataWrapper<V>();
        dataWrapper.setTime(0);
        return dataWrapper;
    }

    /**
     * 重写当前的containsKey，需要判断当前数据是否存在Map中
     * @param key
     * @return
     */
    @Override
    public boolean containsKey(Object key) {
        return super.containsKey(key) || timerRecord.containsKey(key);
    }

    /**
     * 重写进行获取数据
     * @param key
     * @return
     */
    public V getDateByKey(Object key) {
        if (this.containsKey(key)) {
            V ret = super.get(key);
            return ObjectUtils.isEmpty(ret) ? this.timerRecord.get(key).getFuture() : ret;
        }
        return null;
    }

    /**
     * 释放数据(正常业务结束数据)
     * @param key
     * @return
     */
    public void releaseData(K key) {
        super.remove(key);
        this.timerRecord.remove(key);
    }

    /**
     * 对外暴露getter方法
     * @return
     */
    public Integer getExecutionCycleTimer() {
        return executionCycleTimer;
    }

    /**
     * 对外暴露setter方法
     * @return
     */
    public void setExecutionCycleTimer(Integer executionCycleTimer) {
        this.executionCycleTimer = executionCycleTimer;
    }

    /**
     * 初始化数据
     * @param initialCapacity
     * @param loadFactor
     * @param concurrencyLevel
     */
    private void initialize(Integer initialCapacity, Float loadFactor, Integer concurrencyLevel) {

        //初始化计时器
        this.timer.scheduleAtFixedRate(timerTask, 0, this.executionCycleTimer);
        //初始化相关Map数据属性
        if (initialCapacity != null && loadFactor != null && concurrencyLevel != null) {
            this.timerRecord = new ConcurrentHashMap<>(initialCapacity, loadFactor, concurrencyLevel);
        }
        if (initialCapacity != null && loadFactor != null) {
            this.timerRecord = new ConcurrentHashMap<>(initialCapacity, loadFactor);
        }
        if (initialCapacity != null) {
            this.timerRecord = new ConcurrentHashMap<>(initialCapacity);
        } else {
            this.timerRecord = new ConcurrentHashMap<>();
        }
    }


    /**
     * Constructor
     */
    public TimerDataSource() {
        super();
        initialize(null, null, null);

    }

    /**
     * @param initialCapacity
     */
    public TimerDataSource(int initialCapacity) {
        super(initialCapacity);
        initialize(initialCapacity, null, null);
    }

    /**
     * @param initialCapacity
     * @param loadFactor
     */
    public TimerDataSource(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        initialize(initialCapacity, loadFactor, null);

    }

    /**
     * @param initialCapacity
     * @param loadFactor
     * @param concurrencyLevel
     */
    public TimerDataSource(int initialCapacity, float loadFactor, int concurrencyLevel) {
        super(initialCapacity, loadFactor, concurrencyLevel);
        initialize(initialCapacity, loadFactor, concurrencyLevel);
    }


}
